<template>
  <view class="oto-barrage" :style="[customStyle]">
    <view class="txt" v-if="loadingState || barrageRefresh"> 一大波弹幕即将来袭～ </view>
    <view class="oto-barrage-body">
      <template v-for="(item, index) in list">
        <view
          :key="index"
          class="barrage-item"
          :style="[item.style, item.emptyStyle]"
          :data-item="item"
          @transitionend="over(index)"
        >
          <view class="barrage-item-body">
            <view class="user-img">
              <view class="img-box">
                <image :src="item.avatarUrl"></image>
              </view>
            </view>
            <view class="user-text-name">{{ item.nickname || '用户异常' }}:</view>
            <view class="user-text-comment">
              {{ item.content }}
            </view>
          </view>
        </view>
      </template>
    </view>
  </view>
</template>

<script>
  function wait(callback, time = 150) {
    return new Promise((resolve) => {
      const id = setTimeout(() => {
        resolve(callback(id));
      }, time);
    });
  }

  const BARRAGE_STATUS_ENUM = {
    START: 'start',
    STOP: 'stop',
    CONTINUE: 'continue'
  };

  export default {
    props: {
      loopTime: {
        type: Number,
        default: 75
      },
      loopList: {
        type: Array,
        default() {
          return [];
        }
      },
      itemHeight: {
        type: Number,
        default: 86
      },
      loopNum: {
        type: Number,
        default: 3
      },
      customStyle: {
        type: Object,
        default() {
          return {
            height: '274rpx'
          };
        }
      },
      barrageRefresh: {
        type: Boolean,
        default: false
      }
    },
    data() {
      const listIndex = this.loopNum || 3;
      const list = [...Array(this.loopNum).keys()];
      return {
        show: true,
        list,
        widthArr: [],
        animation: null,
        commentList: [],
        userCommentList: [],
        listIndex,
        setTimeoutList: [],
        loadingState: true,
        firstEntry: true
      };
    },
    computed: {
      getUserCommentListLength() {
        return this.userCommentList.length;
      }
    },
    created() {},
    onPageShow() {
      console.log('onPageShow');
      if (!this.firstEntry) {
        this.continue();
        return;
      }
      this.firstEntry = false;
    },
    onPageHide() {
      console.log('onPageHide');
      this.stop();
    },
    methods: {
      async waitToList(list, index, callback) {
        // 循环使用
        const newList = list.slice(index, index + 4);
        const { loopNum } = this;
        if (newList.length !== loopNum) {
          const newLen = loopNum - newList.length;
          list.slice(0, newLen).forEach((item) => {
            newList.push(item);
          });
        }
        const arr = this.getArr();
        for (let i = 0; i < arr.length; i++) {
          const level = arr[i];
          await callback(newList[level], level, newList);
          if (i === 1) {
            this.barrageStatus = BARRAGE_STATUS_ENUM.CONTINUE;
          }
        }
      },
      continue() {
        this.waitToList(this.commentList, this.listIndex, async (item, index) => {
          const data = { ...item, level: index };
          await this.addComment(data, index);
          this.listIndex++;
          await wait(() => {}, this.random(50, 300));
          this.list[index].style.transform = 'translate(-100%, 0)';
        });
      },
      stop() {
        this.barrageStatus = BARRAGE_STATUS_ENUM.STOP;
        this.initListData();
      },
      initListData() {
        this.list = [...Array(this.loopNum).keys()];
      },
      initList() {
        this.initListData();
        if (!this.loadingState) {
          this.loadingState = true;
          this.setRefreshState(!this.loadingState);
        }
      },
      setRefreshState(state) {
        this.$emit('update:barrageRefresh', state);
      },
      async init(commentList) {
        if (!this.loadingState) {
          this.loadingState = true;
          this.setRefreshState(!this.loadingState);
        }
        await wait(() => {
          this.initList();
          const data = {
            widthArr: [],
            animation: null,
            commentList: [],
            userCommentList: [],
            loadingState: true
          };
          Object.keys(data).keys((key) => {
            this[key] = data[key];
            console.log(this[key]);
          });
          this.start(commentList);
        }, 2000); // 加点小延时防止ui还没渲染完
      },
      async start(commentList) {
        console.log('开始执行');
        this.commentList = commentList;
        const arr = this.getArr();
        if (!this.loadingState) {
          this.loadingState = true;
          this.setRefreshState(!this.loadingState);
        }
        for (let i = 0; i < arr.length; i++) {
          const level = arr[i];
          if (i === 1) {
            this.loadingState = false;
          }
          const data = { ...commentList[level], level };
          await this.addComment(data, level);
          console.log('第一个');
          this.listIndex++;
          await wait(() => {}, this.random(50, 300));
          this.list[level].style.transform = 'translate(-100%, 0)';
        }
      },
      getArr() {
        const arr = [...Array(this.loopNum).keys()];
        return this.getArrRandomly(arr);
      },
      getArrRandomly(arr) {
        const len = arr.length;
        //首先从最大的数开始遍历，之后递减
        for (let i = len - 1; i >= 0; i--) {
          //随机索引值randomIndex是从0-arr.length中随机抽取的
          const randomIndex = Math.floor(Math.random() * (i + 1));
          //下面三句相当于把从数组中随机抽取到的值与当前遍历的值互换位置
          const itemIndex = arr[randomIndex];
          arr[randomIndex] = arr[i];
          arr[i] = itemIndex;
        }
        //每一次的遍历都相当于把从数组中随机抽取（不重复）的一个元素放到数组的最后面（索引顺序为：len-1,len-2,len-3......0）
        return arr;
      },
      getRandomWidth(n, m) {
        return this.random(n, m);
      },
      getRanDomTime(str) {
        const len = str.length;
        if (len < 4) {
          return 4;
        } else if (len < 7) {
          return 5;
        } else if (len >= 7 && len < 30) {
          return 6;
        } else {
          return 10;
        }
      },
      deepClone(obj) {
        // 如果是 值类型 或 null，则直接return
        if (typeof obj !== 'object' || obj === null) {
          return obj;
        }

        // 定义结果对象
        let copy = {};
        // 如果对象是数组，则定义结果数组
        if (obj.constructor === Array) {
          copy = [];
        }

        // 遍历对象的key
        for (const key in obj) {
          // 如果key是对象的自有属性
          if (obj.hasOwnProperty(key)) {
            // 递归调用深拷贝方法
            copy[key] = this.deepClone(obj[key]);
          }
        }
        return copy;
      },
      over(index) {
        // 暂停则事件停止执行
        if (this.barrageStatus === BARRAGE_STATUS_ENUM.STOP) return;
        console.log('还在执行弹幕');
        let item = this.deepClone(this.commentList[this.listIndex]);
        if (this.userCommentList.length === 0) {
          if (this.listIndex < this.commentList.length - 1) {
            this.listIndex += 1;
          } else {
            this.listIndex = 0;
          }
        } else {
          item = this.userCommentList.shift();
        }
        if (!item) {
          console.log(this.listIndex);
          item = JSON.parse(JSON.stringify(this.commentList[this.listIndex]));
        }
        if (item.content) {
          item.emptyStyle = {};
        }
        Object.keys(item).forEach((key) => {
          this.$set(this.list[index], key, item[key]);
        });
        this.initListItem(index);
        this.waitToChangeListItem(item, index);
      },
      waitToChangeListItem(item, index) {
        wait(() => {
          this.$set(this.list[index].style, 'transition', `transform ${this.getRanDomTime(item.content)}s linear`);
          wait(() => {
            this.$set(this.list[index].style, 'transform', `translate(-100%, 0)`);
          }, 0);
        }, 200);
      },
      initListItem(index) {
        this.$set(this.list[index].style, 'transition', '');
        this.$set(
          this.list[index].style,
          'transform',
          `translate(${this.getRandomWidth(this.random(103, 120), this.random(135, 150))}vw, 0)`
        );
      },
      random(m, n) {
        //随机在m、n之间的整数
        return Math.round(Math.random() * (n - m)) + m;
      },
      change() {
        this.show = !this.show;
      },
      async addComment(data, level) {
        // this.list[level] = await this.getData(data);
        this.$set(this.list, level, await this.getData(data));
      },
      userAddComment(data) {
        this.$emit('userAddComment', data);
        this.userCommentList.push(data);
        this.commentList.push(data);
      },
      async getData(data) {
        const item = JSON.parse(JSON.stringify(data));
        item.style = {
          top: `${data.level * this.itemHeight}rpx`
        };
        item.tempStyle = {};
        item.style.transform = `translate(${this.getRandomWidth(103, 160)}vw, 0)`;
        await wait(() => {
          item.style.display = 'inline-block';
          if (!item.content) {
            item.emptyStyle.width = '1rpx';
            item.emptyStyle.overflow = 'hidden';
            item.emptyStyle.backgroundColor = 'transparent';
            item.emptyStyle.paddingLeft = '30rpx';
          }
          item.style.transition = `transform ${this.getRanDomTime(item.content || '')}s linear`;
        }, 30);
        console.log('getData', item);
        return item;
      }
    }
  };
</script>
<style>
  @keyframes rightToleft {
    0% {
      transform: translate(103vw, 0);
    }
    100% {
      transform: translate(-100%, 0);
    }
  }
  .right-to-left {
    animation: rightToleft 8s linear;
  }
</style>

<style lang="scss" scoped>
  .oto-barrage {
    width: 100%;
    position: relative;
    padding-top: 25rpx;
    // padding-bottom: 25rpx;

    .txt {
      position: absolute;
      top: 50%;
      left: 50%;
      transform: translate(-50%, -50%);
    }

    .oto-barrage-body {
      width: 100%;
      height: 100%;
      overflow: hidden;
      position: relative;

      .barrage-item {
        display: none;
        transform: translate(103vw, 0);
        position: absolute;
        background-color: rgba(255, 255, 255, 1);
        border-radius: 16rpx;

        .barrage-item-body {
          position: relative;
          min-width: 150rpx;
          padding: 12rpx 35rpx 12rpx 65rpx;
          display: flex;
          align-items: center;
          color: rgba(88, 88, 88, 1);
          font-size: 25rpx;
          .user-img {
            top: 50%;
            left: 0;
            transform: translate(0, -50%);
            position: absolute;
            .img-box {
              display: flex;
              image {
                width: 54rpx;
                height: 54rpx;
                border-radius: 50%;
              }
            }
          }

          .user-text-name {
            border-radius: 23rpx;
            white-space: nowrap;
          }

          .user-text-comment {
            margin-left: 10rpx;
            white-space: nowrap;
            font-weight: 400;
          }
        }
      }
    }
  }
</style>
